
	/************************************************************************************************

	 	Factory: jsl.String
	 	
		Constructors:
			s			String			(s*)								- sid: 7.0
			s			replicate		(n, s*)							- sid: 7.0
																	
		Slicers:
			s			after				(sel, n*, idx*)			- sid: 7.0
			s			before			(sel, n*, idx*)			- sid: 7.0
			c			last				()									- sid: 7.0
			s			left				(n)									- sid: 7.0
			s			right				(n)									- sid: 7.0

		Info:	
			b			contains		(sel, idx*)					- sid: 7.0
			n			index				(sel, n*, idx*)			- sid: 7.0
			a			regexp			(sel, n*, idx*)			- sid: 7.0
			b			endsWith		(sel..)							- sid: 7.0
			b			startsWith	(sel..)							- sid: 7.0
			b			isUpper			()									- sid: 1.0
			b			isLower			()									- sid: 1.0
		
		Operations:
			n			count				(sel, idx*)					- sid: 7.0
			s			compile			(params..)					- sid: 7.0
			s			inject			(s, idx*)						- sid: 7.0
			s			modify			(sel, s, n*, idx*)	- sid: 7.0
			s			padLeft			(n, c*)							- sid: 7.0
			s			padRight		(n, c*)							- sid: 7.0
			s			reverse			()									- sid: 7.0
			s			trim				()									- sid: 7.0
			s			trimLeft		()									- sid: 7.0
			s			trimRight		()									- sid: 7.0					
			s			remove			(sel, n*, idx*)			- sid: 7.0
			s			removeAt		(idx, n*)						- sid: 7.0
																	
		Cosmetic:
			s 		lower				()									- sid: 7.0
			s 		upper				()									- sid: 7.0
		
		Overriding(no in the site):
			it		getIterator	(filter)						- sid: .0
			
		Legend:
			sel	-> selector -> s | re			
																							
	************************************************************************************************/

 	//-------------------------------------------------------------------------------
  jsl.String = function(s) {
 		try {
	   	var proto, rv
    	
			//@d[
      if(arguments.length > 1)	throw jsl.ParamError()
			//@d]
			
			if(arguments.length) {		
				
				if(s instanceof String)
					if(s.__augmented) return s
					else							rv = s
				else
					rv = new String(s)					
			}
			else
				rv = new String
															
			proto = jsl.String.prototype
			
    	for(var id in proto)
    		if(proto.hasOwnProperty(id))
					rv[id] = proto[id]
								
			rv.__native = arguments.callee.__native			
    	return rv	    			
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
  //-------------------------------------------------------------------------------
	jsl.String.__name			= "jsl.String" 
  jsl.String.prototype	= jsl.Object()
  //-------------------------------------------------------------------------------
  jsl.String.replicate  = function(n, s) {
		try {
			var v, s1
			
			//@d[
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(n, "i+", "n")
			if(arguments.length === 2)	jsl.validate(s, "s")
			//@d]
			
			v 	= new Array(n)
			s1	= arguments.length === 2 ? s + "" : " " 
			
			for(var a = 0, l = v.length; a < l; a++)
				v[a] = s1
				
			return v.join("")				
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.after = function(sel, n, idx) {
		try {
			var obj
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 3)	throw jsl.ParamError()
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length >= 2)											jsl.validate(n, "i!0", "n")
			if(arguments.length === 3) 										jsl.validate(idx, "i+", "idx")//@d]
			
			obj = jsl.String.prototype.regexp.apply(this, arguments)		
						
			return obj ? this.slice(obj.index + obj[0].length) : ""
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.before = function(sel, n, idx) {
		try {
			var i
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 3)	throw jsl.ParamError()
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length >= 2)											jsl.validate(n, "i!0", "n")
			if(arguments.length === 3) 										jsl.validate(idx, "i+"	, "idx")//@d]
			
			i = jsl.String.prototype.index.apply(this, arguments)		
						
			return i !== -1 ? this.slice(0, i) : this.slice()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.last = function() {
		try {
			//@d[
      if(!jsl.isString(this))		throw jsl.TypeError("BadMethodCall:String")
			if(arguments.length)			throw jsl.ParamError()//@d]
			
			return this.length ? this.charAt(this.length - 1) : ""
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.left = function(n) {
		try {
			//@d[
      if(!jsl.isString(this))			throw jsl.TypeError("BadMethodCall:String")			
			if(arguments.length !== 1) 	throw jsl.ParamError()
			jsl.validate(n, "i", "n")//@d]
			
			return this.slice(0, n)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.right = function(n) {
		try {
			//@d[
      if(!jsl.isString(this))			throw jsl.TypeError("BadMethodCall:String")			
			if(arguments.length !== 1) 	throw jsl.ParamError()
			jsl.validate(n, "i", "n")//@d]
						
			return n != 0 ? this.slice(-n) : []
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.contains = function(sel, idx) {
		try {
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 2) throw jsl.ParamError()
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length === 2) 										jsl.validate(idx, "i+", "idx")//@d]
						
			return jsl.String.prototype.index.call(this, sel, 1, idx || 0) !== -1
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.index = function(sel, n, idx) {
		try {
			var i, ix, rv, s, re, d, fg
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 3) throw jsl.ParamError()
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length >= 2 && n != "*") 				jsl.validate(n	, "i!0"	, "n")
			if(arguments.length === 3) 										jsl.validate(idx, "i+"	, "idx")//@d]
			
			i 	= +n 		|| 1
			ix	= +idx 	|| 0
			s		= this + ""
			d		= []

			if(sel instanceof RegExp)	{
				
				fg = +sel.ignoreCase + +sel.multiline + +sel.global
				re = RegExp((sel + "").slice(1, -fg - 1), "g" + (sel.ignoreCase ? "i" : "") + (sel.multiline ? "m" : ""))
			}
			else
				re = RegExp(sel.replace(/[\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}]/g, "\\$&"), "g") 
			
			re.lastIndex = ix
			
			do {
				rv = re.exec(s)
			
				if(rv) 
					if(i < 0 || n == "*")	d.push(rv.index)
					else if(!--i)					break 		
				
			} while(rv)						
			
			if(i < 0 && d[d.length + i] != null)	rv = d[d.length + i]
			else if(rv)														rv = rv.index																	
						
			return n == "*" ? (d.length ? d : null) : (rv != null ? rv : -1)				
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.regexp = function(sel, n, idx) {
		try {
			var i, ix, rv, s, re, d, fg
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 3) throw jsl.ParamError()
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length >= 2 && n != "*") 				jsl.validate(n	, "i!0"	, "n")
			if(arguments.length === 3) 										jsl.validate(idx, "i+"	, "idx")//@d]
			
			i 	= +n 		|| 1
			ix	= +idx 	|| 0
			s		= this + ""
			d		= []
			
			if(sel instanceof RegExp) {

				fg = +sel.ignoreCase + +sel.multiline + +sel.global
				re = RegExp((sel + "").slice(1, -fg -1), "g" + (sel.ignoreCase ? "i" : "") + (sel.multiline ? "m" : ""))			
			}
			else
				re = RegExp(sel.replace(/[\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}]/g, "\\$&"), "g") 

			re.lastIndex = ix
			
			do {
				rv = re.exec(s)

				if(rv) 
					if(i < 0 || n == "*")	d.push(rv)
					else if(!--i)					break 		
				
			} while(rv)						
			
			if(i < 0 && d[d.length + i] != null)
				rv = d[d.length + i]
						
			return n == "*" ? (d.length ? d : null) : rv		
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.endsWith = function() {
		try {
			var sel, regexp, obj
			
			//@d[
	    if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length)		throw jsl.ParamError()			
			//@d]

			regexp = jsl.String.prototype.regexp
			
			for(var a = 0, l = arguments.length; a < l; a++) {
				
				sel = arguments[a]
				//@d[
				jsl.validate(sel, "re|s+", "sel[" + a + "]")			
				//@d]
								
				obj = regexp.call(this, sel, -1) 
			
				if(obj && obj.index + obj[0].length === this.length)
					break								
			}
			
			return a < l
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.startsWith = function() {
		try {	
			var sel

			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")			
			if(!arguments.length)		throw jsl.ParamError()			
			//@d]

			for(var a = 0, l = arguments.length; a < l; a++) {
				
				sel = arguments[a]
				//@d[
				jsl.validate(sel, "re|s+", "sel[" + sel + "]")			
				//@d]
				if(sel instanceof RegExp ? !this.search(sel) : !this.indexOf(sel))
					break
			}
			
			return a < l
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}	
  //-------------------------------------------------------------------------------
  jsl.String.prototype.isUpper = function() {
		try {	
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")			
			if(arguments.length)		throw jsl.ParamError()//@d]
			return this == this.toUpperCase()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}	
  //-------------------------------------------------------------------------------
  jsl.String.prototype.isLower = function() {
		try {	
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")			
			if(arguments.length)		throw jsl.ParamError()//@d]
			return this == this.toLowerCase()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}	
  //-------------------------------------------------------------------------------
  jsl.String.prototype.count = function(sel, idx) {
		try {
			var ixs
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()			
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length === 2) 										jsl.validate(idx, "i+", "idx")//@d]
							
			ixs = jsl.String.prototype.index.call(this, sel, "*", idx || 0)
				
			return ixs ? ixs.length : 0
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.compile = function() {
		try {
			var i, args, f

			//@d[
      if(!jsl.isString(this))		throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length)			throw jsl.ParamError()//@d]
			
			i 		= 0
			args	= arguments
			f			= function(v, idx) { return i < args.length ? v.slice(0, -1) + args[i++] : v }
			
			return this.replace(/(?=^|[^\\]|(\\\\)+)\$/g, f)	
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.inject = function(s, idx) {
		try {
			var i
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(s, "s")
			if(arguments.length === 2)										jsl.validate(idx, "i+","idx")//@d]
			
			i = arguments.length === 2 ? +idx : this.length 
			return this.slice(0, i) + s + this.slice(i)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.modify = function(sel, s, n, idx) {
		try {
			var objs, v
			
			//@d[
      if(!jsl.isString(this))														throw jsl.TypeError("BadMethodCall:String")
			if(arguments.length < 2 || arguments.length > 4) 	throw jsl.ParamError()
			jsl.validate(sel, "re|s+"	, "sel")			
			jsl.validate(s	, "s"			, "s")			
			if(arguments.length >= 3 && n != "*") 						jsl.validate(n	, "i!0"	, "n")
			if(arguments.length === 4)												jsl.validate(idx, "i+"	, "idx")//@d]
	
			objs 	= jsl.String.prototype.regexp.call(this, sel, n || 1, idx || 0)
			v 		= this.split("")

			if(objs) {

				objs = n == "*" ? objs : [ objs ]
			
				for(var a = objs.length - 1; a >= 0; a--)
					v.splice(objs[a].index, objs[a][0].length, s)
			}
										
			return v.join("")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.padLeft = function(n, c) {
		try {
			var v, c1, n1
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(n, "i+", "n")			
			if(arguments.length === 2) 										jsl.validate(c, "s+", "c")
			if(arguments.length === 2 && c.length !== 1)	throw jsl.ParamError("BadLength")//@d]
			
			v		= this.split("")
			c1 	= c || " "
			n1	= +n
			
			for(var a = this.length; a < n1; a++)
				v.unshift(c1)
			
			return v.join("")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.padRight = function(n, c) {
		try {
		var v, c1, n1
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(n, "i+", "n")			
			if(arguments.length === 2) 										jsl.validate(c, "s+", "c")
			if(arguments.length === 2 && c.length !== 1)	throw jsl.ParamError("BadLength")//@d]
			
			v		= this.split("")
			c1 	= c || " "
			n1	= +n
			
			for(var a = this.length; a < n1; a++)
				v.push(c1)
			
			return v.join("")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.reverse = function() {
		try {
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")
			if(arguments.length)		throw jsl.ParamError()//@d]

			return this.split("").reverse().join("")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.trim = function() {
		try {
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")			
			if(arguments.length)		throw jsl.ParamError()//@d]

			return this.replace(/^\s+|\s+$/g, "")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.trimLeft = function() {
		try {
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")			
			if(arguments.length)		throw jsl.ParamError()//@d]

			return this.replace(/^\s+/, "")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.trimRight = function() {
		try {
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")
			if(arguments.length)		throw jsl.ParamError()//@d]

			return this.replace(/\s+$/, "")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.remove = function(sel, n, idx) {
		try {
			var objs, v
			
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 3)	throw jsl.ParamError()
			jsl.validate(sel, "re|s+", "sel")			
			if(arguments.length >= 2 && n != "*") 				jsl.validate(n	, "i!0"	, "n")
			if(arguments.length === 3)										jsl.validate(idx, "i+"	, "idx")//@d]
			
			objs 	= jsl.String.prototype.regexp.apply(this, arguments)
			v			= this.split("")
			
			if(objs) {

				objs = n == "*" ? objs : [ objs ]
			
				for(var a = objs.length - 1; a >= 0; a--)
					v.splice(objs[a].index, objs[a][0].length)
			}
			
			return v.join("")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}	
  //-------------------------------------------------------------------------------
  jsl.String.prototype.removeAt = function(idx, n) {
		try {
			//@d[
      if(!jsl.isString(this))												throw jsl.TypeError("BadMethodCall:String")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(idx, "i+", "idx")
			if(arguments.length === 2)										jsl.validate(n, "i+", "n")//@d]
			
			return this.slice(0, idx) + this.slice(idx + (n || 1))
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}	
  //-------------------------------------------------------------------------------
  jsl.String.prototype.lower = function() {
		try {
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")
			if(arguments.length)		throw jsl.ParamError()//@d]

			return this.toLowerCase()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.upper = function() {
		try {
			//@d[
      if(!jsl.isString(this))	throw jsl.TypeError("BadMethodCall:String")
			if(arguments.length)		throw jsl.ParamError()//@d]

			return this.toUpperCase()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.String.prototype.getIterator = function(filter) {
		try {
    	var it, idx, obj
    	//@d[    	    	
      if(!jsl.isString(this))		throw jsl.TypeError("BadMethodCall:String")
      if(arguments.length > 1)	throw jsl.ParamError()
      if(arguments.length)      jsl.validate(filter, "f", "filter")//@d]
			
			it 			= { __name: "jsl.StringIterator" }
			obj			= this.split("")
			idx			= 0
						 
  		//-------------------------------------------------------------------------------
			it.hasNext = function() {
				try {//@d[
					if(arguments.length)	throw jsl.ParamError()//@d]
										
					while(idx < obj.length) {
						
						if(filter ? filter.call(obj, idx + "", obj[idx]) : true)						
							break
						
						idx++
					}

					return idx < obj.length
				}
				catch(e) {
					jsl.throwError(e, this, arguments)
				}
			}
  		//-------------------------------------------------------------------------------
			it.next = function() {
				try {//@d[
					if(arguments.length) throw jsl.ParamError()//@d]
					
					var b = this.hasNext()
					//@d[					
					if(!b)	throw jsl.EndOfIterationError()//@d]
					return obj[idx++]
				}
				catch(e) {
					jsl.throwError(e, this, arguments)
				}
			}
												
      return it

		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	
	//String init
	//-------------------------------------------------------------------------------
	;(function() {
		
		var proto 
		
		//-------------------------------------------------------------------------------
		jsl.String.__native	= jsl.Object.__native.copy().merge(jsl.String.prototype)
		proto								= jsl.String.prototype
			
		for(var id in proto) 
			if(proto.hasOwnProperty(id)) 
				if(id.charAt(0) !== "_" && jsl.isFunction(proto[id]) && !proto[id].__name) {
					
					jsl.String[id] = function(obj) { 
						try {
							
							//@d[
							if(!arguments.length)	throw jsl.ParamError() 
							if(obj === null)			throw jsl.ParamError("NullValue:obj")
							//@d]			
													
							return arguments.callee.__f.apply(obj, Array.prototype.slice.call(arguments, 1)) 
						}
						catch(e) {
							jsl.throwError(e, this, arguments)
						}
					}
				
					jsl.String[id].__name	= id
					jsl.String[id].__f		= proto[id]					
					proto[id].__name 			= id
				}			
	})()	
	